package tech.yixiyun.framework.kuafu.db.sql.handler;

import tech.yixiyun.framework.kuafu.db.DbException;
import tech.yixiyun.framework.kuafu.db.sql.SqlException;
import tech.yixiyun.framework.kuafu.domain.ColumnDefinition;
import tech.yixiyun.framework.kuafu.domain.DomainContext;
import tech.yixiyun.framework.kuafu.domain.DomainDefinition;
import tech.yixiyun.framework.kuafu.domain.annotation.Column;
import tech.yixiyun.framework.kuafu.kits.ClassKit;
import tech.yixiyun.framework.kuafu.kits.Kv;
import org.apache.commons.dbutils.RowProcessor;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

public class BaseRowProcessor implements RowProcessor {

    public static final BaseRowProcessor INSTANCE = new BaseRowProcessor();

    /**
     * 普通pojo类的结构
     */
    private static final Map<Class, Map<String, ColumnDefinition>> POJOS = new ConcurrentHashMap();

    /**
     * 取消某个POJO类的缓存
     * @param clazz
     */
    public static void unregister(Class clazz) {
        POJOS.remove(clazz);
    }



    @Override
    public Object[] toArray(ResultSet rs) throws SQLException {
        return new Object[0];
    }

    @Override
    public <T> T toBean(ResultSet rs, Class<? extends T> type) throws SQLException {
        return createBean(rs, type);
    }

    @Override
    public <T> List<T> toBeanList(ResultSet rs, Class<? extends T> type) throws SQLException {
        List<T> results = new ArrayList<T>();

        if (!rs.next()) {
            return results;
        }

        do {
            results.add(this.createBean(rs, type));
        } while (rs.next());

        return results;
    }

    private <T> T createBean(ResultSet rs, Class<? extends T> type) {

        if (type == Kv.class) { //如果返回结果要求是Kv类型
            Kv kv = Kv.create();
            kv.putAll(this.toMap(rs));
            return (T) kv;
        }

        if (type == Map.class) {
            return (T) this.toMap(rs);
        }


        if (type == LinkedHashMap.class) {
            return (T) this.toMap(rs);
        }

        if (type == HashMap.class) {
            HashMap<String, Object> map = new HashMap<>();
            map.putAll(this.toMap(rs));
            return (T) map;
        }




        Map<String, ColumnDefinition> columnMap = null;
        DomainDefinition definition = DomainContext.getDomainDefinition(type);
        if (definition != null) { //是Domain类
            columnMap = definition.getColumnMap();
        } else { //
            columnMap = POJOS.computeIfAbsent(type, k -> {
                Map<String, ColumnDefinition> cols = new HashMap<>();
                List<Field> fields = ClassKit.getFields(type);
                for (Field field : fields) {
                    Column columnAnno = field.getDeclaredAnnotation(Column.class);
                    //临时字段不能在这里忽略,会导致查询是无法赋值
                    //if (columnAnno != null && columnAnno.isTemp()) continue;

                    int modifiers = field.getModifiers();
                    if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)
                            || Modifier.isPublic(modifiers)) {
                        continue;
                    }
                    ColumnDefinition column = new ColumnDefinition(field, columnAnno);
                    cols.put(column.getName(), column);
                }
                return cols;
            });
        }
        T bean = newInstance(type);
        try {

            ResultSetMetaData metaData = rs.getMetaData();
            ColumnDefinition column = null;
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                String columnLabel = metaData.getColumnLabel(i);
                column = columnMap.get(columnLabel);
                if (column == null) {
                    continue;
                }
                Object value = ColumnProcessor.process(rs, columnLabel, column.getField().getGenericType());
                column.getField().set(bean, value);

            }

        } catch (Exception e) {
            throw new SqlException("构建bean实例发生异常", e);
        }


        return bean;
    }


    protected <T> T newInstance(Class<T> c) {
        try {
            return c.newInstance();

        } catch (InstantiationException e) {
            throw new SqlException(
                    "无法创建" + c.getName() + "实例: ", e);

        } catch (IllegalAccessException e) {
            throw new SqlException(
                    "无法创建" + c.getName() + "实例: ", e);
        }
    }

    @Override
    public Map<String, Object> toMap(ResultSet rs)  {
        try {
            Map<String, Object> result = new LinkedHashMap<>();
            ResultSetMetaData rsmd = rs.getMetaData();
            int cols = rsmd.getColumnCount();

            for (int i = 1; i <= cols; i++) {
                String columnName = rsmd.getColumnLabel(i);
                if (null == columnName || 0 == columnName.length()) {
                    columnName = rsmd.getColumnName(i);
                }
                result.put(columnName, rs.getObject(i));
            }

            return result;
        } catch (SQLException e) {
            throw new DbException(e);
        }
    }
}
